import os.path
import locale
import wx
import wx.lib.newevent

# ---------- My Modules ---------- #
import fileDragAndDrop
import optionVar

# ---------- Events ---------- #
(EventFileListOpenFile, EVT_FILELIST_OPENFILE) = wx.lib.newevent.NewEvent()


class DragTargetToFileList(fileDragAndDrop.DropTarget):
	def openFile(self, filePath):
		self.window.eventOpenFile(filePath)
		
	def addDirectory(self, dirPath):
		self.window.AddItem(dirPath, True, False, False)


class FileListCtrl(wx.TreeCtrl):
	def __init__(self,
				 parent,
				 font='',
				 folderIcon='',
				 folderOpenIcon='',
				 scriptFolderIcon='',
				 scriptFolderOpenIcon='',
				 normalFileIcon='',
				 pythonIcon='',
				 melIcon=''):
		# Japanese windows, it will be cp932
		self.coding=locale.getpreferredencoding()
		
		self.parent = parent
		self.MENU_ADD_DIRECTORY = wx.NewId()
		self.MENU_TC_FILEOPEN = wx.NewId()
		self.MENU_TC_FILERENAME = wx.NewId()
		self.MENU_TC_FILEDELETE = wx.NewId()
		self.MENU_TC_SHOWHIERARCHY = wx.NewId()
		self.MENU_TC_SHOWALLEXT = wx.NewId()
		self.MENU_TC_REFRESHSCRIPTDIR = wx.NewId()
		self.MENU_TC_DISCONNECT = wx.NewId()
		self.MENU_TC_SORT = wx.NewId()
		self.MENU_TC_SORT_FILENAME = wx.NewId()
		self.MENU_TC_SORT_FILETYPE = wx.NewId()
		wx.TreeCtrl.__init__(self, self.parent, -1,
							 wx.Point(0, 0), wx.Size(160, 250),
						   wx.TR_DEFAULT_STYLE | wx.NO_BORDER)
		#self = wx.TreeCtrl(parent, -1, wx.Point(0, 0), wx.Size(160, 250),
		#				   wx.TR_DEFAULT_STYLE | wx.NO_BORDER)
		imglist = wx.ImageList(16, 16, True, 2)
		self.fldridx = imglist.Add(folderIcon)
		self.fldropenidx = imglist.Add(folderOpenIcon)
		self.fileidx = imglist.Add(normalFileIcon)
		self.pyidx = imglist.Add(pythonIcon)
		self.melidx = imglist.Add(melIcon)
		self.scriptDiridx = imglist.Add(scriptFolderIcon)
		self.scriptDirOpenidx = imglist.Add(scriptFolderOpenIcon)
		self.AssignImageList(imglist)
		
		# fileName, fileType, fileSize, fileDate
		if optionVar.hasOption('fileSortType'):
			self.fileSort = optionVar.getOption('fileSortType')
		else:
			self.fileSort='fileType'
		
		self.root = self.AddRoot("Script Directories", 0)
		
		# ----- Appearance ----- #
		if optionVar.hasOption('FileList_FontColour'):
			self.fontColour = optionVar.getOption('FileList_FontColour')
		else:
			self.fontColour = '#000000'
		if optionVar.hasOption('FileList_BGColour'):
			BGColour = optionVar.getOption('FileList_BGColour')
		else:
			BGColour = '#FAE1FA'
		self.SetColour(BGColour)
		
		self.font = font
		if type(self.font) == wx._gdi.Font:
			self.SetItemFont(self.root, self.font)
			self.SetItemTextColour(self.root, self.fontColour)
		items = []
		
		self.scriptDirList = []
		self.scriptDirCtrl = []
		self.scriptDirShowHierarchy = []
		self.scriptDirShowAllExtension = []
		self.scriptFileList = []
		i = 0
		while optionVar.hasOption('DirectoryList' + str(i)):
			savedDir = optionVar.getListOption('DirectoryList' + str(i))
			if len(savedDir)<4: continue
			if savedDir[2]==1:
				showHierarchy=True
			else:
				showHierarchy=False
			if savedDir[3]==1:
				showAllExtension=True
			else:
				showAllExtension=False
			self.AddItem(savedDir[0],
						 savedDir[1],
						 showHierarchy,
						 showAllExtension)
			i += 1
		self.Expand(self.root)
		
		# ----- Bind ----- #
		self.Bind(wx.EVT_LEFT_DCLICK, self.OnDClick)
		self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
		
		# ----- D&D ----- #
		dt = DragTargetToFileList(self)
		self.SetDropTarget(dt)
		
	def eventOpenFile(self, filePath):
		evt = EventFileListOpenFile(filePath=filePath)
		wx.PostEvent(self.parent, evt)
		
	def AddItem(self, dirPath, expand, showHierarchy, showAllExtension):
		if not os.path.isdir(dirPath):
			return None
		
		if type(dirPath)==str:
			dirPath=unicode(dirPath, self.coding)
		
		self.scriptDirList.append(dirPath)
		self.scriptDirShowHierarchy.append(showHierarchy)
		self.scriptDirShowAllExtension.append(showAllExtension)
		dirName = os.path.split(dirPath)[-1]
		dirName_display = dirName+u' ('+ dirPath +u')'
		self.scriptDirCtrl.append(self.AppendItem(self.root, dirName_display, 0))
		newID = len(self.scriptDirList)-1
		if type(self.font) == wx._gdi.Font:
			self.SetItemFont(self.scriptDirCtrl[newID], self.font)
			self.SetItemTextColour(self.scriptDirCtrl[newID],
										self.fontColour)
		self.SetPyData(self.scriptDirCtrl[newID], None)
		self.SetItemImage(self.scriptDirCtrl[newID],
							   self.scriptDiridx,
							   wx.TreeItemIcon_Normal)
		self.SetItemImage(self.scriptDirCtrl[newID],
							   self.scriptDirOpenidx,
							   wx.TreeItemIcon_Expanded)
		if showAllExtension:
			ext  = '*'
		else:
			ext = ['py', 'mel']
		self.TreeAdd( self.scriptDirCtrl[newID], self.scriptDirList[newID],
					  hierarchy = showHierarchy,
					  ext = ext)
		if expand:
			self.Expand(self.scriptDirCtrl[newID])
		
	def ScriptDirContentsRemove(self, id):
		# remove all files from self.scriptFileList
		removeID = []
		for f in range(len(self.scriptFileList)):
			if self.GetItemParent(self.scriptFileList[f][0])==self.scriptDirCtrl[id]:
				removeID.append(f)
		removeID.reverse()
		for i in removeID:
			del self.scriptFileList[i]
		self.DeleteChildren(self.scriptDirCtrl[id])
		
	def ScriptDirRemove(self, id):
		self.ScriptDirContentsRemove(id)
		self.Delete(self.scriptDirCtrl[id])
		del self.scriptDirList[id]
		del self.scriptDirCtrl[id]
		del self.scriptDirShowHierarchy[id]
		del self.scriptDirShowAllExtension[id]
		
	def ScriptDirRefresh(self, id):
		self.ScriptDirContentsRemove(id)
		if self.scriptDirShowAllExtension[id]:
			ext  = '*'
		else:
			ext = ['py', 'mel']
		self.TreeAdd( self.scriptDirCtrl[id], self.scriptDirList[id],
					  hierarchy = self.scriptDirShowHierarchy[id],
					  ext = ext)
		
	def __sortedListDir(self, path, sortType):
		fileList = []
		dirList = []
		for fileName in os.listdir(path):
			if os.path.isdir(os.path.join(path,fileName)):
				dirList.append({'fileName':fileName})
			else:
				fileList.append({'fileName':fileName, 'fileType':fileName.split('.')[-1], 'fileSize':os.path.getsize(os.path.join(path,fileName))})
		dirList.sort(key=lambda h : h['fileName'])
		#fileList.sort(key=lambda h : h[sortType])
		if sortType=='fileName':
			fileList.sort(key=lambda h : h['fileName'])
		else:
			fileList.sort(key=lambda h : h['fileName'])
			fileList.sort(key=lambda h : h['fileType'])
		res = []
		for dirName in dirList:
			res.append(dirName['fileName'])
		for fileName in fileList:
			res.append(fileName['fileName'])
		return res
		
	def TreeAdd(self, parent, path, hierarchy = True, ext = ['py', 'mel']):
		for fileName in self.__sortedListDir(path, self.fileSort):
			fullpath = path + os.sep + fileName
			if os.path.isdir(fullpath) and hierarchy:
				data =  self.AppendItem(parent, fileName, 0)
				if type(self.font) == wx._gdi.Font:
					self.SetItemFont(data, self.font)
					self.SetItemTextColour(data, self.fontColour)
				self.SetPyData(data, None)
				self.SetItemImage(data,
									   self.fldridx,
									   wx.TreeItemIcon_Normal)
				self.SetItemImage(data,
									   self.fldropenidx,
									   wx.TreeItemIcon_Expanded)
				
				self.TreeAdd( data, fullpath, hierarchy, ext)
				continue
			thisExt = os.path.splitext(fileName)[1][1:]
			if thisExt.lower()=='py':
				data =  self.AppendItem(parent, fileName, self.pyidx)
				self.scriptFileList.append((data, fullpath))#ctrl, filePath
				if type(self.font) == wx._gdi.Font:
					self.SetItemFont(data, self.font)
					self.SetItemTextColour(data, self.fontColour)
			elif thisExt.lower()=='mel':
				data =  self.AppendItem(parent, fileName, self.melidx)
				self.scriptFileList.append((data, fullpath))#ctrl, filePath
				if type(self.font) == wx._gdi.Font:
					self.SetItemFont(data, self.font)
					self.SetItemTextColour(data, self.fontColour)
			elif ext == '*' or ext == '*.*':
				data =  self.AppendItem(parent, fileName, self.fileidx )
				self.scriptFileList.append((data, fullpath))#ctrl, filePath
				if type(self.font) == wx._gdi.Font:
					self.SetItemFont(data, self.font)
					self.SetItemTextColour(data, self.fontColour)
			elif thisExt.lower() in ext:
				data =  self.AppendItem(parent, fileName, self.fileidx )
				self.scriptFileList.append((data, fullpath))#ctrl, filePath
				if type(self.font) == wx._gdi.Font:
					self.SetItemFont(data, self.font)
					self.SetItemTextColour(data, self.fontColour)
					
	def SaveDirSettings(self):
		if not len(self.scriptDirList):
			return None
		# save current dirs for next start up
		maxLen = 0
		for i in range(len(self.scriptDirList)):
			expand = self.IsExpanded(self.scriptDirCtrl[i])
			showHierarchy = self.scriptDirShowHierarchy[i]
			showAllExtension = self.scriptDirShowAllExtension[i]
			data = [self.scriptDirList[i],
					expand,
					showHierarchy,
					showAllExtension]
			optionVar.saveOption('DirectoryList'+str(i), data)
			maxLen = i
		# clear others:
		maxLen += 1
		while optionVar.hasOption('DirectoryList' + str(maxLen)):
			res = optionVar.removeOption('DirectoryList'+str(maxLen))
			maxLen += 1
			
	def OnDClick(self, event):
		pt = event.GetPosition();
		item, flags = self.HitTest(pt)
		if item:
			if self.GetItemText(item) == 'Script Directories':
				pass
			elif self.IsScriptDir(item) != -1:
				pass
			else:
				self.eventOpenFile(self.GetFilePathFromData(item))
		event.Skip() 
	
	def OnRightDown(self, event):
		pt = event.GetPosition();
		item, flags = self.HitTest(pt)
		if item:
			self.SelectItem(item)#?
			if self.GetItemText(item) == 'Script Directories':
				self.Menu()
			elif self.IsScriptDir(item) != -1:
				self.CurrentDirId = self.IsScriptDir(item)
				self.ScriptDirMenu()
			else:
				self.CurrentFilePath = self.GetFilePathFromData(item)
				self.FileMenu()
			self.SelectItem(item)#?
		
	def IsScriptDir(self, data):
		if data in self.scriptDirCtrl:
			return self.scriptDirCtrl.index(data)
		else:
			return -1
		
	def GetFilePathFromData(self, data):
		for s in self.scriptFileList:
			if s[0]==data:
				return s[1]
		return None
		
	def Menu(self):
		menu = wx.Menu()
		menu.Append(self.MENU_ADD_DIRECTORY, "Add Directory")
		self.Bind(wx.EVT_MENU, self.OnLoadDir,
				  id=self.MENU_ADD_DIRECTORY)
		self.PopupMenu(menu)
		menu.Destroy()
		
	def ScriptDirMenu(self):
		menu = wx.Menu()
		menu.Append(self.MENU_ADD_DIRECTORY, "Search From Contents")
		menu.Append(self.MENU_TC_REFRESHSCRIPTDIR, "Refresh")
		menu.AppendSeparator()
		self.showHierarchyObj = menu.Append(self.MENU_TC_SHOWHIERARCHY,
											"Show Hierarchy",
											"Show Hierarchy",
											kind = wx.ITEM_CHECK)
		if self.scriptDirShowHierarchy[self.CurrentDirId]:
			menu.Check(self.MENU_TC_SHOWHIERARCHY, True)
			
		self.showAllExtensionObj = menu.Append(self.MENU_TC_SHOWALLEXT,
											   "Show All Extensions",
											   "Show All File",
											   kind = wx.ITEM_CHECK)
		if self.scriptDirShowAllExtension[self.CurrentDirId]:
			menu.Check(self.MENU_TC_SHOWALLEXT, True)
			
		# Sort
		sortMenu = wx.Menu()
		sortMenu.Append(self.MENU_TC_SORT_FILENAME, "File name", kind = wx.ITEM_CHECK)
		sortMenu.Append(self.MENU_TC_SORT_FILETYPE, "File type", kind = wx.ITEM_CHECK)
		menu.AppendMenu(self.MENU_TC_SORT, "Sort", sortMenu)
		
		if self.fileSort=='fileName':
			sortMenu.Check(self.MENU_TC_SORT_FILENAME, True)
		else:
			sortMenu.Check(self.MENU_TC_SORT_FILETYPE, True)
			
		menu.AppendSeparator()
		menu.Append(self.MENU_TC_DISCONNECT, "Disconnect")
		# ----- Enable/Disable ----- #
		menu.Enable(self.MENU_ADD_DIRECTORY, False)
		# ----- Bind ----- #
		self.Bind(wx.EVT_MENU, self.OnRefreshScriptDir,
				  id=self.MENU_TC_REFRESHSCRIPTDIR)
		self.Bind(wx.EVT_MENU, self.OnShowHierarchy,
				  id=self.MENU_TC_SHOWHIERARCHY)
		self.Bind(wx.EVT_MENU, self.OnShowAllExtension,
				  id=self.MENU_TC_SHOWALLEXT)
		self.Bind(wx.EVT_MENU, self.OnDisconnect,
				  id=self.MENU_TC_DISCONNECT)
		self.Bind(wx.EVT_MENU, self.OnSortFileName,
				  id=self.MENU_TC_SORT_FILENAME)
		self.Bind(wx.EVT_MENU, self.OnSortFileType,
				  id=self.MENU_TC_SORT_FILETYPE)
		
		self.PopupMenu(menu)
		menu.Destroy()
		
	def OnRefreshScriptDir(self, event):
		self.ScriptDirRefresh(self.CurrentDirId)
		
	def OnShowHierarchy(self, event):
		if self.showHierarchyObj.IsChecked():
			self.scriptDirShowHierarchy[self.CurrentDirId]=True
		else:
			self.scriptDirShowHierarchy[self.CurrentDirId]=False
		self.ScriptDirRefresh(self.CurrentDirId)
		
	def OnShowAllExtension(self, event):
		if self.showAllExtensionObj.IsChecked():
			self.scriptDirShowAllExtension[self.CurrentDirId]=True
		else:
			self.scriptDirShowAllExtension[self.CurrentDirId]=False
		self.ScriptDirRefresh(self.CurrentDirId)
		
	def OnDisconnect(self, event):
		self.ScriptDirRemove(self.CurrentDirId)
		self.SaveDirSettings()
		#self.tree.DeleteAllItems()
		# and have to refresh
		
	def OnSortFileName(self, event):
		self.fileSort='fileName'
		optionVar.saveOption('fileSortType', 'fileName')
		for i in range(len(self.scriptDirList)):
			self.ScriptDirRefresh(i)
	
	def OnSortFileType(self, event):
		self.fileSort='fileType'
		optionVar.saveOption('fileSortType', 'fileType')
		for i in range(len(self.scriptDirList)):
			self.ScriptDirRefresh(i)
	
	def FileMenu(self):
		menu = wx.Menu()
		menu.Append(self.MENU_TC_FILEOPEN, "Open")
		menu.Append(self.MENU_TC_FILERENAME, "Rename")
		menu.Append(self.MENU_TC_FILEDELETE, "Delete")
		# ----- Enable/Disable ----- #
		menu.Enable(self.MENU_TC_FILERENAME, False)
		menu.Enable(self.MENU_TC_FILEDELETE, False)
		# ----- Bind ----- #
		self.Bind(wx.EVT_MENU, self.OnFileOpen,
				  id=self.MENU_TC_FILEOPEN)
		self.PopupMenu(menu)
		menu.Destroy()
		
	def OnFileOpen(self, event):
		self.eventOpenFile(self.CurrentFilePath)
		
	def OnLoadDir(self, event):
		dlg = wx.DirDialog(self, "Choose a directory:",
						  style=wx.DD_DEFAULT_STYLE
						   #| wx.DD_DIR_MUST_EXIST
						   #| wx.DD_CHANGE_DIR
						   )
		if dlg.ShowModal() == wx.ID_OK:
			newPath = dlg.GetPath()
			newDir = os.path.split(newPath)[-1]
			if not newDir == u"":
				self.AddItem(newPath, True, False, False)
		dlg.Destroy()
		
	def IsNewFilePath(self, path):
		"""
		If this path is in self.scriptDirList or child of directory,
		return False.
		"""
		if type(path)==str:
			path=unicode(path, self.coding)
			
		for d in self.scriptDirList:
			if path.startswith(d):
				return False
		return True
	
	# ----- Appearance ----- #
	def GetFont(self):
		return self.font
	
	def GetTextColour(self):
		return self.fontColour
	
	def GetColour(self):
		return self.GetBackgroundColour()
	
	def SetFont(self, newFont):
		self.font = newFont
		self.SetItemFont(self.root, newFont)
		# directory items
		for c in self.scriptDirCtrl:
			self.SetItemFont(c, newFont)
		# script items
		for s in self.scriptFileList:
			self.SetItemFont(s[0], newFont)
			
	def SetTextColour(self, col):
		self.fontColour = col
		self.SetItemTextColour(self.root, col)
		# directory items
		for c in self.scriptDirCtrl:
			self.SetItemTextColour(c, col)
		# script items
		for s in self.scriptFileList:
			self.SetItemTextColour(s[0], col)
	
	def SetColour(self, col):
		self.SetBackgroundColour(col)
